package com.vineetmanohar.nitrogen;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import com.google.gson.Gson;

/**
 * ObjectModel represents a POJO model.
 * 
 * Model maybe loaded from an XML file, YAML, JSON, database or directly built
 * in Java. Once loaded in memory, the Model object represents the data in
 * Hierarchical form and is meant to be passed to the code generation engine.
 * 
 * @author vineetmanohar
 */
public class ObjectModel extends HashMap<String, Model> implements
		WritableModel {
	private static final long serialVersionUID = 1L;

	public ObjectModel() {
	}

	public boolean isPrimitive() {
		return false;
	}

	public static void main(String[] args) {
		ObjectModel objectModel = new ObjectModel();

		ObjectModel entities = new ObjectModel();
		ObjectModel boatEntity = new ObjectModel();
		boatEntity.put("id", ModelFactory.createPrimitive("boat"));
		ArrayModel entityList = new ArrayModel();
		entityList.add(boatEntity);
		entities.put("entity", entityList);

		objectModel.put("entities", entities);

		Gson gson = new Gson();
		System.out.println(gson.toJson(objectModel));
	}

	public ObjectModel getObjectModel() {
		return this;
	}

	public boolean isObject() {
		return true;
	}

	public boolean isArray() {
		return false;
	}

	public ArrayModel getArrayModel() {
		throw new NitrogenException(this + " is not an array", null);
	}

	public PrimitiveModel getPrimitive() {
		throw new NitrogenException(this + " is not a primitive", null);
	}

	private Model parent;

	public Model getParent() {
		return parent;
	}

	public void setParent(Model parent) {
		this.parent = parent;
	}

	private String modelName;

	public String getModelName() {
		if (isRoot()) {
			return "";
		}

		if (parent != null && parent.isArray()) {
			return parent.getArrayModel().getModelName();
		}

		return modelName;
	}

	public void setModelName(String modelName) {
		this.modelName = modelName;
	}

	public void addChild(String name, WritableModel writableModel) {
		writableModel.setParent(this);
		writableModel.setModelName(name);
		put(name, writableModel);
	}

	public boolean isRoot() {
		return this.parent == null;
	}

	public int getDepth() {
		return ModelUtils.getDepth(this);
	}

	@Override
	public String toString() {
		StringBuilder sb = new StringBuilder();

		List<Model> rootToNode = new ArrayList<Model>();

		Model curr = this;
		while (curr != null) {
			rootToNode.add(0, curr);
			curr = curr.getParent();
			if (curr != null && curr.isArray()) {
				curr = curr.getParent();
			}
		}

		for (Model model : rootToNode) {
			sb.append(model.getModelName());
			if (model.isObject()) {
				// print attributes to further qualify the path
				ObjectModel objectModel = model.getObjectModel();
				for (String key : objectModel.keySet()) {
					Model child = objectModel.get(key);
					if (child.isPrimitive()) {
						sb.append("[" + key + "="
								+ child.getPrimitive().getValueAsString() + "]");
					}
				}
			}
			sb.append("/");
		}

		return sb.toString();
	}
}